package com.changsideal.core;

import com.amazonaws.AmazonClientException;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.model.*;
import com.amazonaws.util.StringInputStream;
import com.changsideal.core.exception.OstClientException;
import com.changsideal.entity.I;
import com.changsideal.entity.P;
import com.changsideal.tool.BucketValidator;
import com.changsideal.tool.Constant;
import com.changsideal.util.BucketUtil;
import com.changsideal.util.PropertyUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.io.*;
import java.util.Date;
import java.util.List;
import java.util.Properties;

/**
 * @ClassName EasyOperate
 * @Description TODO
 * @Author Create by Chansideal.Haosc
 * @Date 2019/6/14 17:47
 * @Version 1.2
 **/
@Slf4j
public final class EasyOperate implements S3Template {
    private final ThreadLocal<AmazonS3> S3 = new ThreadLocal<>();
    private String version;
    private P pSelf;
    private I iIN;

    private String bucketName;
    private String[] bucketKey;
    private String downloadPath;
    private String metaDataKey;
    private String metaDataValue;
    private String content;
    private File destFile;
    private CannedAccessControlList fileType;

    public EasyOperate(I iIN, String version) {
        this.iIN = iIN;
        this.version = version;
        this.bucketKey = iIN.getBucketKey();
        this.bucketName = iIN.getBucketName();
        this.downloadPath = iIN.getDownloadPath();
        this.content = iIN.getContent();
        this.destFile = iIN.getDestFile();
        this.fileType = iIN.getFileType();
        this.metaDataKey = iIN.getMetaDataKey();
        this.metaDataValue = iIN.getMetaDataValue();
        connect();
    }

    public EasyOperate(P pSelf, I iIN, String version) {
        this.pSelf = pSelf;
        this.iIN = iIN;
        this.version = version;
        this.bucketKey = iIN.getBucketKey();
        this.bucketName = iIN.getBucketName();
        this.downloadPath = iIN.getDownloadPath();
        this.content = iIN.getContent();
        this.destFile = iIN.getDestFile();
        this.fileType = iIN.getFileType();
        this.metaDataKey = iIN.getMetaDataKey();
        this.metaDataValue = iIN.getMetaDataValue();
        connect();
    }

    @Override
    public void connect() {
        if (S3.get() == null) {
            if (StringUtils.isBlank(version)) {
                log.error("客户端版本号:,{}未指定，连接终止！", version);
                throw new OstClientException("参数对象p为空，创建AmazonClient连接失败！");
            }
            String localConfig = getPropertiesConfig();
            if (StringUtils.isNotBlank(localConfig)) {
                if (Constant.LOCAL_CONFIG_ON.equals(localConfig)) {
                    pSelf = P.build();
                }
                if (Constant.LOCAL_CONFIG_OFF.equals(localConfig)) {
                    if (this.pSelf == null) {
                        log.error("参数对象p为空，创建AmazonClient连接失败！");
                        throw new OstClientException("参数对象p为空，创建AmazonClient连接失败！");
                    }
                }
                createVersionClient();
                log.info("{}版本客户端连接建立成功", version);
            } else {
                log.warn("未获取到配置{}相关信息，建立连接终止！", Constant.AWS_CONFIG_OPEN);
                return;
            }
        } else {
            log.warn("{}建立复用客户端信息成功", version);
        }
    }

    private void createVersionClient() {
        switch (version) {
            case Constant.AMAZON_V2:
                S3.set(S3Factory.getS3ClientWithV2Signatures(pSelf));
                break;
            case Constant.AMAZON_V4:
                S3.set(S3Factory.getS3ClientWithV4Signatures(pSelf));
                break;
            default:
                log.error("{}版本客户端创建失败", version);
        }
    }

    @Override
    public Boolean produce() {
        boolean bFlag = false;
        if (create() != null) {
            bFlag = true;
        }
        return bFlag;
    }

    @Override
    public Boolean produceMetaData() {
        boolean bFlag = false;
        if (createMetaData() != null) {
            bFlag = true;
        }
        return bFlag;
    }

    @Override
    public void download() {
        checkAmazonClientState();
        S3Object object = null;
        byte[] data = null;
        for(String bucketKey : bucketKey) {
        	object = S3.get().getObject(new GetObjectRequest(bucketName, bucketKey));
        	if (object != null) {
                try (InputStream input = object.getObjectContent()) {
                    try (FileOutputStream fileOutputStream = new FileOutputStream(downloadPath)) {
                        data = new byte[input.available()];
                        int len = 0;
                        while ((len = input.read(data)) != -1) {
                            fileOutputStream.write(data, 0, len);
                        }
                        log.info("根据bucketKey: {} 从bucketName: {}下载" + "文件成功，存储路径: {}", bucketKey, bucketName, downloadPath);
                    }
                } catch (IOException | OstClientException e) {
                    log.error("amazonS3下载文件异常 " + e.getMessage(), e);
                }
            }else {
            	continue;
            }
        }
    }

    @Override
    public Boolean easyDownload() {
        boolean flag = false;
        GetObjectRequest request = null;
        try {
        	for(String bucketKey : bucketKey) {
        		request = new GetObjectRequest(bucketName, bucketKey);
                S3.get().getObject(request, new File(downloadPath));
                flag = true;
        	}
        } catch (Exception ase) {
            log.error("amazonS3下载文件异常 " + ase.getMessage(), ase);
        }
        return flag;
    }

    @Override
    public Boolean remove() {
        checkAmazonClientState();
        boolean bFlag = true;
        try {
        	for(String bucketKey : bucketKey) {
        		if (BucketValidator.checkBucketInfoExits(S3.get(), bucketName, bucketKey)) {
                    S3.get().deleteObject(bucketName, bucketKey);
                    if (BucketValidator.checkBucketInfoExits(S3.get(), bucketName, bucketKey)) {
                        bFlag = false;
                        log.warn("从bucketName: {}获取bucketKey:{}失败。", bucketName, bucketKey);
                    } else {
                        log.info("从bucketName: {}获取bucketKey:{}成功。", bucketName, bucketKey);
                    }
                } else {
                    bFlag = false;
                    log.warn("从bucketName: {}获取bucketKey:{}不存在。", bucketName, bucketKey);
                }
        	}
        } catch (AmazonClientException e) {
            log.error("删除信息异常:{}", e.getMessage());
        }
        return bFlag;
    }

    @Override
    public PutObjectResult create() {
        checkAmazonClientState();
        PutObjectResult result = null;
        
        try (StringInputStream stream = new StringInputStream("")) {
        	for(String bucketKey : bucketKey) {
        		if (BucketValidator.checkBucketMetaData(S3.get(), bucketName, bucketKey)) {
                    log.warn("bucketName:{}中已存在bucketKey:{}，创建元数据失败。", bucketName, bucketKey);
                    return result;
                }
                ObjectMetadata metadata = new ObjectMetadata();
                metadata.addUserMetadata(bucketKey, bucketName);
                metadata.setContentLength(0);
                result = S3.get().putObject(bucketName, bucketKey, stream, metadata);
                if (BucketValidator.checkBucketMetaData(S3.get(), bucketName, bucketKey)) {
                    log.info("bucketName:{},bucketKey:{}，创建元数据成功。", bucketName, bucketKey);
                } else {
                    log.warn("bucketName:{},bucketKey:{}，创建元数据失败。", bucketName, bucketKey);
                    result = null;
                }
            }
        } catch (IOException | AmazonClientException e) {
            log.error(e.getMessage());
        }
        return result;
    }

    @Override
    public ObjectMetadata createMetaData() {
        checkAmazonClientState();
        ObjectMetadata metadata = null;
        StringInputStream inputStream = null;
        try {
        	for(String bucketKey : bucketKey) {
	            if (BucketValidator.checkBucketMetaData(S3.get(), bucketName, bucketKey)) {
	                metadata = new ObjectMetadata();
	                metadata.setContentLength(content.length());
	                inputStream = new StringInputStream(content);
	                S3.get().putObject(bucketName, bucketKey, inputStream, metadata);
	                if (!BucketValidator.checkBucketContent(S3.get(), bucketName, bucketKey)) {
	                    metadata = null;
	                }
	            }
        	}
        } catch (UnsupportedEncodingException e) {
            log.error(e.getMessage());
        } finally {
            if (null != inputStream) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    log.error(e.getMessage());
                }
            }
        }
        return metadata;
    }

    @Override
    public Boolean upload() {
        checkAmazonClientState();
        boolean bFlag = false;
        try {
        	for(String bucketKey : bucketKey) {
	            if (BucketValidator.checkBucketInfoExits(S3.get(), bucketName)) {
	                BucketUtil.createBucket(S3.get(), bucketName);
	            }
	            S3.get().putObject(new PutObjectRequest(bucketName, bucketKey, destFile).withCannedAcl(fileType));
	            bFlag = true;
        	}
        } catch (Exception ase) {
            log.error("amazonS3上传文件File模式异常 " + ase.getMessage(), ase);
        }
        return bFlag;
    }

    @Override
    public List<S3ObjectSummary> getFilesByBucketName(String bucketName) {
        ObjectListing objects = S3.get().listObjects(bucketName);
        return objects.getObjectSummaries();
    }

    public AmazonS3 getClient() {
        return S3.get();
    }

    public String getShortConnect(Integer expiration) {
        String reUrl = null;
        GeneratePresignedUrlRequest httpRequest = null;
        try {
        	for(String bucketKey : bucketKey) {
	            httpRequest = new GeneratePresignedUrlRequest(bucketName, bucketKey);
	            httpRequest.setExpiration(new Date(System.currentTimeMillis() + expiration * 1000));
	            reUrl = String.valueOf(S3.get().generatePresignedUrl(httpRequest));
        	}
        } catch (Exception e) {
            log.error("amazonS3获取短链接异常 " + e.getMessage(), e);
        }
        return reUrl;
    }

    public String getLongConnect() {
        String url = null;
        GeneratePresignedUrlRequest urlRequest = null;
        try {
        	for(String bucketKey : bucketKey) {
	            urlRequest = new GeneratePresignedUrlRequest(bucketName, bucketKey);
	            url = String.valueOf(S3.get().generatePresignedUrl(urlRequest)).split("\\?")[0];
	            if (url.indexOf(bucketKey) == -1) {
	                throw new RuntimeException("url文件名称校验不合法");
	            }
        	}
        } catch (Exception e) {
            log.error("amazonS3获取长链接异常 " + e.getMessage(), e);
        }
        return url;
    }

    private String getPropertiesConfig() {
        String configResult = null;
        Properties properties = PropertyUtil.getProperty(Constant.AWS_CONFIG_NAME);
        if (properties != null) {
            configResult = PropertyUtil.getConfigString(properties, Constant.AWS_CONFIG_OPEN);
        } else {
            log.warn("未获取到配置：[" + Constant.AWS_CONFIG_NAME + "]相关信息");
        }
        return configResult;
    }

    private void checkAmazonClientState() {
        if (S3.get() == null) {
            throw new OstClientException("客户端信息为空，请先初始化再行操作！");
        }

    }

    @Override
    public Object query() {
        checkAmazonClientState();
        S3Object s3Object = null;
        S3ObjectInputStream s3ObjectInputStream = null;
        String content = null;
        try (InputStreamReader inputStreamReader = new InputStreamReader(s3ObjectInputStream)) {
            try (BufferedReader reader = new BufferedReader(inputStreamReader)) {
            	for(String bucketKey : bucketKey) {
            		s3Object = S3.get().getObject(bucketName, bucketKey);
                    if ((s3ObjectInputStream = s3Object.getObjectContent()) != null) {
                        content = reader.readLine();
                        log.info("bucketName：{}," + "bucketKey：{},得到内容是：{}", bucketName, bucketKey, content);
                    }	
            	}
            }
        } catch (Exception e) {
            log.error(e.getMessage());
        } finally {
            try {
                if (s3ObjectInputStream != null) {
                    s3ObjectInputStream.close();
                }
            } catch (IOException | AmazonClientException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        return s3Object;
    }

    @Override
    public void close() {
        if (S3.get() != null) {
            S3.remove();
        }
    }

    @Override
    public String toString() {
        return "EasyOperate{" +
                "version='" + version + '\'' +
                ", pSelf=" + pSelf +
                ", iIN=" + iIN +
                ", bucketName='" + bucketName + '\'' +
                ", bucketKey='" + bucketKey + '\'' +
                ", downloadPath='" + downloadPath + '\'' +
                ", metaDataKey='" + metaDataKey + '\'' +
                ", metaDataValue='" + metaDataValue + '\'' +
                ", content='" + content + '\'' +
                ", destFile=" + destFile +
                ", fileType=" + fileType +
                '}';
    }
}
